package com.mongo.config;

import com.mongodb.WriteConcern;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Collections;

/**
 * MongoTemplate配置
 *
 * @author 王霄
 * @date 2021/1/13
 */
@Configuration
public class MongoConfig {

    /**
     * 自定义转换器
     */
    @Component
    @WritingConverter
    public static class BigDecimalToDouble implements Converter<BigDecimal, Double> {
        @Override
        public Double convert(BigDecimal bigDecimal) {
            return bigDecimal.doubleValue();
        }
    }

    /**
     * 加载自定义转换器
     */
    @Bean
    public MongoCustomConversions mongoCustomConversions(BigDecimalToDouble bigDecimalToDouble) {
        return new MongoCustomConversions(Collections.singletonList(bigDecimalToDouble));
    }

    /**
     * 加载映射转换器
     */
    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory factory, MongoMappingContext context, MongoCustomConversions conversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        //添加自定义的转换器
        mappingConverter.setCustomConversions(conversions);
        //去掉默认mapper添加的_class
        mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return mappingConverter;
    }

    /**
     * 初始化MongoTemplate
     * <p>
     * WriteConcern.NONE:没有异常抛出
     * WriteConcern.NORMAL:仅抛出网络错误异常，没有服务器错误异常
     * WriteConcern.SAFE:抛出网络错误异常、服务器错误异常；并等待服务器完成写操作。
     * WriteConcern.MAJORITY: 抛出网络错误异常、服务器错误异常；并等待一个主服务器完成写操作。
     * WriteConcern.FSYNC_SAFE: 抛出网络错误异常、服务器错误异常；写操作等待服务器将数据刷新到磁盘。
     * WriteConcern.JOURNAL_SAFE:抛出网络错误异常、服务器错误异常；写操作等待服务器提交到磁盘的日志文件。
     * WriteConcern.REPLICAS_SAFE:抛出网络错误异常、服务器错误异常；等待至少2台服务器完成写操作。
     * </p>
     */
    @Bean
    public MongoTemplate mongoTemplate(MongoDatabaseFactory factory, MappingMongoConverter converter) {
        MongoTemplate mongoTemplate = new MongoTemplate(factory, converter);
        mongoTemplate.setWriteConcern(WriteConcern.MAJORITY);
        return mongoTemplate;
    }
}
